unit oConfigManager;

{
	created   8.3.2010
	author    Miroslav Mintal
	purpose   holds and manages Config

	edit list:
}

interface

uses
  oManager, Classes, Generics.Collections, oProcessItem, SysUtils, XMLDoc,
  XMLIntf, oEntity, oProcessObjects;

type
  EConfigManager = class(Exception)
  end;

  ENotValidConfigType = class(EConfigManager)
  end;

  TConfigManager = class(TManager)
    private
      aConfigs: TList<TConfignData>;
      function search(paName: String): TConfignData;
      procedure SaveOne(paWhere: IXMLNode; paConfig: TConfignData);
      procedure LoadOne(paFrom: IXMLNode);
      procedure Unload;
    public
      property Configs: TList<TConfignData> read aConfigs;
      constructor Create(paMaster: TManager);
      destructor Destroy; override;
      function ProcessObject(paItem: TProcessItem):TProcessItem; override; final;
      procedure Save(paWhere: IXMLNode);
      procedure Load(paFrom: IXMLNode);
  end;

implementation

uses
  oProcessObjectConstants;

resourcestring eConfigManNotValidType = 'not a valid processing type';

{ TPedestrianManager }

constructor TConfigManager.Create(paMaster: TManager);
begin
  aMaster := paMaster;
  aConfigs := TList<TConfignData>.Create;
end;

destructor TConfigManager.Destroy;
var
  I: Integer;
begin
  inherited;
  for I := 0 to aConfigs.Count - 1 do
    aConfigs[I].Free;
  aConfigs.Free;
end;

function TConfigManager.ProcessObject(paItem: TProcessItem): TProcessItem;
var
  config : TConfignData;
  strings: TStringList;
  node: IXMLNode;
begin
  result := nil;

  case paItem.Code of

    PO_CONFIG_INSERT:
    begin
      try
        if not(paItem.Data is TConfignData) then raise ENotValidConfigType.Create(eConfigManNotValidType);
        aConfigs.Add(paItem.Data as TConfignData);
        aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_CONFIGS, NIL));
      except
        on E:ENotValidConfigType do raise EConfigManager.Create(eConfigManNotValidType);
        on E:EConfigManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_CONFIG_REMOVE:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidConfigType.Create(eConfigManNotValidType);
        config := search((paItem.Data as TString).String_);
        aConfigs.Extract(config).Free;
        aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_SAVE_CONFIGS, NIL));
      except
        on E:ENotValidConfigType do raise EConfigManager.Create(eConfigManNotValidType);
      end;
    end;

    PO_CONFIG_GET_CONFIG:
    begin
      try
        if not(paItem.Data is TString) then raise ENotValidConfigType.Create(eConfigManNotValidType);
        config := search((paItem.Data as TString).String_);
        if config <> nil then
          Result := TProcessItem.create(PO_SUCCESS, config)
        else
          Result := TProcessItem.create(PO_FAILURE, nil);
      except
        on E:ENotValidConfigType do raise EConfigManager.Create(eConfigManNotValidType);
        on E:EConfigManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_CONFIG_GET_NAMES : begin
      strings := TStringList.Create;
      for config in aConfigs do
        strings.Add(config.Name);
      Result := TProcessItem.create(PO_SUCCESS, TProcessingStrings.Create(strings));
    end;

    PO_CONFIG_SAVE:
    begin
      try
        if not(paItem.Data is TProcessingXML) then raise ENotValidConfigType.Create(eConfigManNotValidType);
        node := ((paItem.Data) as TProcessingXML).Node;
        Save(node);
        result := TProcessItem.create(PO_SUCCESS, nil);
        paItem.Free;
      except
        on E:ENotValidConfigType do raise EConfigManager.Create(eConfigManNotValidType);
        on E:EConfigManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_CONFIG_LOAD:
    begin
      try
        if not(paItem.Data is TProcessingXML) then raise ENotValidConfigType.Create(eConfigManNotValidType);
        node := ((paItem.Data) as TProcessingXML).Node;
        Load(node);
        result := TProcessItem.create(PO_SUCCESS, nil);
        paItem.Free;
      except
        on E:ENotValidConfigType do raise EConfigManager.Create(eConfigManNotValidType);
        on E:EConfigManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

    PO_CONFIG_UNLOAD:
    begin
      try
        if (paItem.Data <> nil) then raise ENotValidConfigType.Create(eConfigManNotValidType);
        Unload;
        paItem.Free;
      except
        on E:ENotValidConfigType do raise EConfigManager.Create(eConfigManNotValidType);
        on E:EConfigManager do result := TProcessItem.create(PO_FAILURE,nil);
      end;
    end;

  end; //Case
end;

procedure TConfigManager.Save(paWhere: IXMLNode);
var
  PriNode: IXMLNode;
  I: Integer;
begin
  PriNode := paWhere.AddChild('Configs');
  PriNode.Attributes['count'] := aConfigs.Count;
  for I := 0 to aConfigs.Count - 1 do
  begin
    PriNode := paWhere.AddChild('Config');
    SaveOne(PriNode, aConfigs[I]);
  end;
end;

procedure TConfigManager.SaveOne(paWhere: IXMLNode; paConfig: TConfignData);
var
  ConfigTypeNode, SecNode: IXMLNode;
  I: Integer;
begin
  ConfigTypeNode := paWhere.AddChild('Name');
  ConfigTypeNode.Attributes['name'] := paConfig.Name;
  ConfigTypeNode := paWhere.AddChild('FL');
  ConfigTypeNode.Attributes['name'] := paConfig.FL;
  ConfigTypeNode := paWhere.AddChild('LL');
  ConfigTypeNode.Attributes['name'] := paConfig.LL;
  ConfigTypeNode := paWhere.AddChild('Paths');
  ConfigTypeNode.Attributes['name'] := paConfig.Paths;
  ConfigTypeNode := paWhere.AddChild('Ped');
  ConfigTypeNode.Attributes['name'] := paConfig.Ped;
  ConfigTypeNode := paWhere.AddChild('Arr');
  ConfigTypeNode.Attributes['name'] := paConfig.Arr;
  ConfigTypeNode := paWhere.AddChild('Arrivals');
  ConfigTypeNode.Attributes['count'] := paConfig.Arrivals.Count;
  for I := 0 to paConfig.Arrivals.Count - 1 do
  begin
    SecNode := ConfigTypeNode.AddChild('Arrival');
    SecNode.Attributes['name'] := paConfig.Arrivals[I];
  end;
  ConfigTypeNode := paWhere.AddChild('RunConfig');
  ConfigTypeNode.Attributes['name'] := paConfig.RunConfig;
end;

function TConfigManager.search(paName: String): TConfignData;
var
  config: TConfignData;
begin
  for config in Configs do
    if config.Name = paName then
    begin
      //we found it, let's return it and exit function
      result := config;
      exit;
    end;
  result := nil;
end;

procedure TConfigManager.Unload;
var
  I: Integer;
begin
  for I := 0 to aConfigs.Count - 1 do
    aConfigs[I].Free;
  aConfigs.Free;
  aConfigs := TList<TConfignData>.Create;
end;

procedure TConfigManager.Load(paFrom: IXMLNode);
var
  PriNode: IXMLNode;
  count : Integer;
  I: Integer;
begin
  Unload;
  // kvoli genialnemu tagu data v subore ktore si moje kody musia 27 zmyslom zistit asi sami ked si ho tam niekdo sam od seba prida ...
  PriNode := paFrom.ChildNodes.First;
  count := PriNode.Attributes['count'];
  PriNode := PriNode.NextSibling;
  for I := 0 to count - 1 do
  begin
    LoadOne(PriNode.ChildNodes.First);
    PriNode := PriNode.NextSibling;
  end;
end;

procedure TConfigManager.LoadOne(paFrom: IXMLNode);
var
  PriNode, SecNode: IXMLNode;
  config: TConfignData;
  arriv: TStringList;
  name, FL, LL, Paths, Ped, Arr, RC: String;
  count: Integer;
  I: Integer;
begin
  PriNode := paFrom;
  arriv := TStringList.Create;

  name := PriNode.Attributes['name'];
  PriNode := PriNode.NextSibling;
  FL := PriNode.Attributes['name'];
  PriNode := PriNode.NextSibling;
  LL := PriNode.Attributes['name'];
  PriNode := PriNode.NextSibling;
  Paths := PriNode.Attributes['name'];
  PriNode := PriNode.NextSibling;
  Ped := PriNode.Attributes['name'];
  PriNode := PriNode.NextSibling;
  Arr := PriNode.Attributes['name'];
  PriNode := PriNode.NextSibling;
  count := PriNode.Attributes['count'];
  SecNode := PriNode.ChildNodes.First;
  for I := 0 to count - 1 do
  begin
     arriv.Add(SecNode.Attributes['name']);
     SecNode := SecNode.NextSibling;
  end;

  PriNode := PriNode.NextSibling;
  RC := PriNode.Attributes['name'];

  config := TConfignData.Create(FL, LL, Paths, Ped, Arr, arriv, RC, name);
  aConfigs.Add(config);
end;

end.
